Improve compression of Emacs packages on Android 2.2
authorPo Lu <luangruo@yahoo.com>
Wed, 12 Jun 2024 05:52:33 +0000 (13:52 +0800)
committerPo Lu <luangruo@yahoo.com>
Wed, 12 Jun 2024 05:52:33 +0000 (13:52 +0800)
* configure.ac (ZIP): Search for a `zip' executable and
substitute the same if targeting SDK 8.

* java/INSTALL: Document new requirement.

* java/Makefile.in (GZIP_PROG, ZIP): New substitutions.
(.PHONY): Delete references to directory-tree.

(install_temp): On SDK 8 and earlier, compress large *.el and
Info files with gzip, and divide install_temp into three
separate directories, with one for large files, another for
gzipped files, and one more for the remainder.
(install_temp/assets/directory-tree, install_temp/assets/version)
(install_temp/assets/build_info): Merge these rules into
install_tmp, that they may execute before the assets directory
is split.
(emacs.apk-in): Package each directory separately, accounting
for their varied compression requirements.

* lisp/term/android-win.el (input-decode-map): Define select to
return in input-decode-map.

configure.ac
java/INSTALL
java/Makefile.in
lisp/term/android-win.el

index 1754ca4f977908ea83f1723b2dcda7e85e819a9b..f75c0a98820b846316b8cbbe2e180d90c982f995 100644 (file)
@@ -878,6 +878,7 @@ AC_ARG_VAR([JAVAC], [Java compiler path.  Used for Android.])
 AC_ARG_VAR([JARSIGNER], [Java package signer path.  Used for Android.])
 AC_ARG_VAR([APKSIGNER], [Android package signer path.  Used for Android.])
 AC_ARG_VAR([SDK_BUILD_TOOLS], [Path to the Android SDK build tools.])
+AC_ARG_VAR([ZIP], [Path to the `zip' utility.])
 
 if test "$with_android" = "yes"; then
    AC_MSG_ERROR([Please specify the path to the Android.jar file, like so:
@@ -1223,8 +1224,13 @@ package will likely install on older systems but crash on startup.])
   ANDROID_SDK_8_OR_EARLIER=
   if test "$android_sdk" -le "8"; then
      ANDROID_SDK_8_OR_EARLIER=yes
+     AC_CHECK_PROGS([ZIP], [zip])
+     AS_IF([test -z "$ZIP"],
+       [AC_MSG_ERROR([The `zip' utility is required for generating \
+packages targeting Android 2.2.])])
   fi
   AC_SUBST([ANDROID_SDK_8_OR_EARLIER])
+  AC_SUBST([ZIP])
 
   # Save confdefs.h and config.log for now.
   mv -f confdefs.h _confdefs.h
index 1d6f1535647b382fb13cb826dee29ca1767dd5a2..91916c6586cae59f2785cddb71262e6be4721c09 100644 (file)
@@ -158,10 +158,13 @@ the NDK r10b or later.  We wanted to make Emacs work on even older
 versions of Android, but they are missing the required JNI graphics
 library that allows Emacs to display text from C code.
 
-Due to an extremely nasty bug in the Android 2.2 system, the generated
-Emacs package cannot be compressed in builds for Android 2.2.  As a
-result, the Emacs package will be approximately 100 megabytes larger
-than a compressed package for a newer version of Android.
+There is an extremely nasty bug in the Android 2.2 system, the upshot of
+which is that large files within the generated Emacs package cannot be
+compressed in builds for Android 2.2, so that the Emacs package will be
+approximately 15 megabytes larger than a compressed package for a newer
+version of Android.  For such systems the `zip' utility is also required
+to produce packages that will not be misinterpreted by the package
+manager.
 
 \f
 BUILDING C++ DEPENDENCIES
index 802da0b9e36d22ee6458f1509a2788eacad6a2d3..20d595eb3ca83df156bebdf7ae0e0d07a341d764 100644 (file)
@@ -44,10 +44,20 @@ ANDROID_JAR = @ANDROID_JAR@
 ANDROID_ABI = @ANDROID_ABI@
 ANDROID_SDK_18_OR_EARLIER = @ANDROID_SDK_18_OR_EARLIER@
 ANDROID_SDK_8_OR_EARLIER = @ANDROID_SDK_8_OR_EARLIER@
+ZIP = @ZIP@
 WARN_JAVAFLAGS = @WARN_JAVAFLAGS@
 JAVAFLAGS = $(WARN_JAVAFLAGS) -classpath "$(ANDROID_JAR):$(srcdir)"
 FIND_DELETE = @FIND_DELETE@
 
+ifneq (,$(ANDROID_SDK_8_OR_EARLIER))
+# gzip is invoked to compress installed .el and some .txt files, on SDK
+# 8 and earlier, where ZIP compression is unavailable.
+GZIP_PROG = @GZIP_PROG@
+else
+GZIP_PROG =
+endif
+
+
 # Android 4.3 and earlier require Emacs to be signed with a different
 # digital signature algorithm.
 
@@ -188,7 +198,7 @@ $(libsrc)/asset-directory-tool:
 # There is no need to depend on NDK_BUILD_SHARED as libemacs.so
 # does already.
 
-.PHONY: install_temp install_temp/assets/directory-tree
+.PHONY: install_temp
 install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
        $(AM_V_GEN)
 # Make the working directory for this stuff
@@ -223,6 +233,54 @@ install_temp: $(CROSS_BINS) $(CROSS_LIBS) $(RESOURCE_FILES)
          rm -rf $${subdir}/[mM]akefile*[.-]in ;                \
          rm -rf $${subdir}/Makefile;                           \
        done
+# Compress files if AAPT otherwise will not.
+       $(AM_V_SILENT)                                          \
+       [ -z "${GZIP_PROG}" ] || {                              \
+         echo "Compressing large *.el *.info etc. ..." &&      \
+         cd "install_temp/assets/lisp" &&                      \
+         for f in `find . -name "*.elc" \( -size +1536 -o      \
+                     -size 1536 \) -print                      \
+                   | sed 's/.elc$$/.el/'`; do                  \
+           ${GZIP_PROG} -9n "$$f";                             \
+         done;                                                 \
+         ${GZIP_PROG} -9n "../etc/publicsuffix.txt";           \
+         find ../info -name "*.elc" -size 1536 -o -size +1536  \
+          | xargs ${GZIP_PROG} -9n ;                           \
+       }
+# Produce metadata files providing build information and suchlike.
+       $(AM_V_SILENT)                                          \
+       { (cd $(top_srcdir)                                     \
+          && git rev-parse HEAD || echo "Unknown")             \
+          && (git rev-parse --abbrev-ref HEAD                  \
+              || echo "Unknown") } 2> /dev/null >              \
+         install_temp/assets/version
+       $(AM_V_SILENT)                                          \
+       { hostname; date +%s; } > install_temp/assets/build_info
+# Produce the file index.
+       $(AM_V_SILENT) $(libsrc)/asset-directory-tool           \
+         install_temp/assets install_temp/assets/directory-tree
+# If the package targets Android 2.2, move compressable and
+# non-compressable assets to separate directories.
+       $(AM_V_SILENT)                                          \
+       if [ -z "${ANDROID_SDK_8_OR_EARLIER}" ]; then :; else   \
+         echo "Moving large and gzipped files to separate directories...">&2;\
+         mkdir -p install_temp/assets_raw;                     \
+         cd install_temp/assets;                               \
+         find . \( -size +1536 -o -size 1536 \)                \
+           \( \! -name '*.gz' \) -type f > files.txt;          \
+         tar cf ../assets_raw/largefiles.tar -T files.txt;     \
+         cat files.txt | xargs rm;                             \
+         cd ../assets_raw && tar xf largefiles.tar             \
+           && rm largefiles.tar;                               \
+         cd ..;                                                \
+         mkdir -p assets_gz;                                   \
+         find assets -name '*.gz' -type f > files.txt;         \
+         tar cf assets_gz/gzfiles.tar -T files.txt;            \
+         cat files.txt | xargs rm;                             \
+         cd assets_gz && tar xf gzfiles.tar                    \
+           && rm gzfiles.tar;                                  \
+         rm ../assets/files.txt;                               \
+       fi
 # Generate the directory tree for those directories.
 # Install architecture dependents to lib/$(ANDROID_ABI).  This
 # perculiar naming scheme is required to make Android preserve these
@@ -252,35 +310,43 @@ ifneq ($(NDK_BUILD_SHARED),)
          install_temp/lib/$(ANDROID_ABI)
 endif
 
-install_temp/assets/directory-tree: $(libsrc)/asset-directory-tool \
-  install_temp install_temp/assets/version                        \
-  install_temp/assets/build_info
-       $(AM_V_GEN) $(libsrc)/asset-directory-tool install_temp/assets \
-         install_temp/assets/directory-tree
-
-install_temp/assets/version: install_temp
-       $(AM_V_GEN) { (cd $(top_srcdir)                                 \
-                       && git rev-parse HEAD || echo "Unknown")        \
-                       && (git rev-parse --abbrev-ref HEAD             \
-                           || echo "Unknown") } 2> /dev/null > $@
-
-install_temp/assets/build_info: install_temp
-       $(AM_V_GEN) { hostname; date +%s; } > $@
-
-emacs.apk-in: install_temp install_temp/assets/directory-tree  \
-  AndroidManifest.xml install_temp/assets/version             \
-  install_temp/assets/build_info classes.dex
+emacs.apk-in: install_temp AndroidManifest.xml classes.dex
 # Package everything.  Redirect the generated R.java to install_temp, as
 # it must already have been generated as a prerequisite of
-# classes.dex's.
-       $(AM_V_AAPT) $(AAPT) p -I "$(ANDROID_JAR)" -F $@   \
-         -f -M AndroidManifest.xml $(AAPT_ASSET_ARGS)     \
-         -A install_temp/assets                           \
-         -S $(top_srcdir)/java/res -J install_temp
+# classes.dex's.  If ANDROID_SDK_8_OR_EARLIER, compress those files
+# which are smaller than 1536 blocks (i.e. 768 kib), the maximum the
+# asset manager on such old systems can decompress.
+#
+# The elaborate dance with zip serves to disable the automatic
+# decompression of *.gz files in aapt.
+#
+# One more consideration is that timestamps should be preserved in
+# packaged libraries, as on Android 2.2 the package manager retains
+# existing libraries from previous installations if a new package's
+# libraries are not more recent.
+       $(AM_V_AAPT)                                            \
+       if [ -z "$(ANDROID_SDK_8_OR_EARLIER)" ]; then           \
+         $(AAPT) p -I "$(ANDROID_JAR)" -F $@                   \
+           -f -M AndroidManifest.xml $(AAPT_ASSET_ARGS)        \
+           -A install_temp/assets                              \
+           -S $(top_srcdir)/java/res -J install_temp;          \
+         cd install_temp;                                      \
+           $(AAPT) add ../$@ `find lib -type f`;               \
+       else                                                    \
+         echo "Packaging files not eligible for compression...">&2;\
+         $(AAPT) p -I "$(ANDROID_JAR)" -F $@                   \
+           -f -M AndroidManifest.xml -A install_temp/assets_raw\
+           -S $(top_srcdir)/java/res -J install_temp -0 "";    \
+         echo "Packaging files eligible for compression...">&2;\
+         cd install_temp; find assets -type f                  \
+           | xargs $(ZIP) ../$@ &> /dev/null;                  \
+         echo "Packagging files already compressed...">&2;     \
+         cd assets_gz; find assets -type f                     \
+           | xargs $(ZIP) ../../$@ &> /dev/null;               \
+         echo "Packaging shared libraries and code..." >&2;    \
+         cd ..; $(ZIP) ../$@ `find lib -type f`;               \
+       fi
        $(AM_V_SILENT) $(AAPT) a $@ classes.dex
-       $(AM_V_SILENT) pushd install_temp &> /dev/null; \
-         $(AAPT) add ../$@ `find lib -type f`;         \
-       popd &> /dev/null
        $(AM_V_SILENT) rm -rf install_temp
 
 # Makefile itself.
index 3e0f71abf91cf710fd55eb19c56f0d0a66a13b61..0d2d0299282f3e13e4e77d11aa37398d46c4d03f 100644 (file)
@@ -627,6 +627,9 @@ accessible to other programs."
 (global-set-key [\83] #'ignore) ; KEYCODE_NOTIFICATION on pre-Honeycomb
                                 ; releases.
 
+;; `select' key, which I suppose amounts to return.
+(define-key input-decode-map [select] [return])
+
 \f
 (provide 'android-win)
 ;; android-win.el ends here.